﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Skylabs.Ssl;
using System.Text.RegularExpressions;

using agkn;

namespace Skylabs.ACL
{
    [Serializable]
    public enum color
    {
        // Summary:
        //     The color black.
        Black = 0,
        //
        // Summary:
        //     The color dark blue.
        DarkBlue = 1,
        //
        // Summary:
        //     The color dark green.
        DarkGreen = 2,
        //
        // Summary:
        //     The color dark cyan (dark blue-green).
        DarkCyan = 3,
        //
        // Summary:
        //     The color dark red.
        DarkRed = 4,
        //
        // Summary:
        //     The color dark magenta (dark purplish-red).
        DarkMagenta = 5,
        //
        // Summary:
        //     The color dark yellow (ochre).
        DarkYellow = 6,
        //
        // Summary:
        //     The color gray.
        Gray = 7,
        //
        // Summary:
        //     The color dark gray.
        DarkGray = 8,
        //
        // Summary:
        //     The color blue.
        Blue = 9,
        //
        // Summary:
        //     The color green.
        Green = 10,
        //
        // Summary:
        //     The color cyan (blue-green).
        Cyan = 11,
        //
        // Summary:
        //     The color red.
        Red = 12,
        //
        // Summary:
        //     The color magenta (purplish-red).
        Magenta = 13,
        //
        // Summary:
        //     The color yellow.
        Yellow = 14,
        //
        // Summary:
        //     The color white.
        White = 15,
    }
    public class acl : ICommandParse
    {
        public SSL ssl;
        //public AGK agk = new AGK(AGK.sf);
        public COMMANDS[] commands = new COMMANDS[100];
        public COM_WINDOW window;
        public VARIABLES glob;
        public string window_title = "";
        public class COM_WINDOW 
        {
            public string title = "";
            public color back_color = color.Black;
            public color for_color = color.Gray;
            public string prompt = ":";
            
            public COM_WINDOW(string title,color back_color,color for_color,string prompt)
            {    
                this.title = title;
                this.back_color = back_color;
                this.for_color = for_color;
                this.prompt = prompt;
            }
            
        }
        public class COMMANDS
        {
            public string name { get; set; }
            public string[] desc { get; set; }
            public string script { get; set; }
            public COMMANDS(string name, string[] desc){
                this.name = name;
                this.desc = desc;
            }
        }     
        public acl(){
            glob = new VARIABLES();
            //glob["cheese"].Value = 1;
            //glob["case"].Value = false;
            //glob["filling"].Value = "no thanks.";
            ssl = new SSL(ref glob);
            ssl.add_global("cheese", 1);
            ssl.add_global("case", false);
            ssl.add_global("filling", "no thanks.");
        }
        public int add_command (string name, string strDesc){
            return add_command(name,new string[]{strDesc});
        }
        public int add_command( string name, string[] desc)
        {
            int ret = 0;
            bool gotone = false;
            for (ret = 0; ret <commands.Length; ret++)
            {
                if (commands[ret] == null)
                {
                    gotone = true;
                    break;
                }
            }
            if (gotone == true)
            {
                Array.Resize(ref commands, commands.Count() + 1);
                commands[ret] = new COMMANDS(name, desc);
            }
            if (gotone == false) ret = -1;
            return ret;
        }
        public void add_command(int cID, string name, string[] desc)
        {
            commands[cID] = new COMMANDS(name, desc);
        }
        public void add_command(int cID, string name, string desc)
        {
            commands[cID] = new COMMANDS(name, new string[]{desc});
        }
        public void init(string title, color back_color, color for_color, string prompt)
        {
            window = new COM_WINDOW(title, back_color, for_color, prompt);
            add_command(98, "/?", "Display this command list.");
            add_command(99, "/quit", "Exit the program.");
        }
        //Main loop. Returns bool true when it ends.
        public bool Loop()
        {
            //sline("-AGK-", "_", color.DarkGray, color.Black, color.Gray, color.Black);
            stext(window.prompt, color.Yellow, color.DarkYellow,false);
            Console.ForegroundColor = (ConsoleColor)color.White;
            Console.BackgroundColor = (ConsoleColor)color.Black;
            return arg_handle();
        }

        private bool arg_handle()
        {
            bool ret = false;
            bool fail = false;
            COMMANDARRAY ca = new COMMANDARRAY();
            ca.ParseCommands(Console.ReadLine());
            switch (ca.name)
            {
                case "quit":
                    ret = true;
                    anykey("quit");
                    break;
                case "?":
                    chelp();
                    break;
                case "start":
                    //agk.Init();
                    //ca2 = com2.Split(csep2, StringSplitOptions.RemoveEmptyEntries);
                    //System.Threading.Thread T = new System.Threading.Thread(agk.Init);
                    //T.SetApartmentState(System.Threading.ApartmentState.MTA);
                    stext("Starting 'game'...", color.Cyan, color.Black, true);
                    //T.Start();
                    break;
                case "tobyte":
                    for (int c = 0; c < ca.list.Count(); c++)
                    {
                        string from = ca[c].name.Substring(1, ca[c].name.Length - 1);
                        //int start = ca.raw_command.LastIndexOf(' ')+1;
                        //int end = ca.raw_command.Length - start;
                        string butt = "Byte{" + c.ToString() + "} : ";
                        char[] butter = from.ToCharArray();
                        for (int b = 0; b < from.Length; b++)
                        {
                            Byte bt = Convert.ToByte(butter[b]);
                            butt = butt + "-" + bt.ToString();
                        }
                        stext(butt, color.Red, color.Black, true);
                    }
                    break;
                case "frombyte":
                    for (int c = 0; c < ca.list.Count(); c++)
                    {                        
                        //Byte bt = Convert.ToByte(ca[c].name);
                        string from = ca[c].name.Substring(1, ca[c].name.Length - 1);
                        string butt = "";
                        try
                        {
                            Byte bt = Convert.ToByte(from);
                            
                            butt = Convert.ToString(Convert.ToChar(bt));
                        }
                        catch (Exception b)
                        {
                            butt = "FAIL!";
                        }
                        stext("FromB{" + c.ToString() + "} : " + butt, color.Red, color.Black, true);
                    }
                    break;
                case "bytes":
                    int failz = 0;
                    int sex = 0;
                    string[] savez = new string[] { };
                    internal_work.FILE file = new internal_work.FILE();
                    string buttl = "";
                    while (failz < 1000)
                    {
                        buttl = "Byte{" + sex.ToString() + "} : ";
                        try
                        {
                            Byte bt = Convert.ToByte(sex);
                            buttl = buttl + Convert.ToString(Convert.ToChar(bt));
                            Array.Resize(ref savez, sex + 1);
                            savez[sex] = buttl;
                            stext(buttl, color.Red, color.Black, true);
                        }
                        catch (Exception E)
                        {
                            failz++;
                            //buttl = "FAIL!";
                        }
                        sex++;

                        
                    }
                    //file.write_temp_file(savez, "c:\\butt.txt", true);
                    break;
                case "binary":

                    break;
                #region script case
                case "script":
                    for (int i=0;i<ca.list.Count();i++){
                        switch (ca.list[i].name)
                        {
                            case "load":
                                ssl.load_script_files(false);
                                break;

                            case "run":
                                for (int c = 0; c < ca.list[i].subsets.Count(); c++)
                                {
                                    if (ssl.scripts[ca.list[i].subsets[c].name.Trim(new char[2] { '\'', '"' })].lines != null)
                                    {
                                        ssl.scripts[ca.list[i].subsets[c].name.Trim(new char[2] { '\'', '"' })].run();
                                    }
                                }
                                break;
                            case "dglob":
                                this.sline("[Stored Globals]", "-", color.Green, color.DarkGreen, color.White, color.Black);
                                for (int d = 0; d < ssl.globals.count; d++)
                                {
                                    if (ssl.globals[d].Static == true)
                                    {
                                        this.stext("STATIC", color.Blue, color.Black, false);
                                    }
                                    this.stext("<", color.Cyan, color.DarkMagenta, false);
                                    this.stext(ssl.globals[d].ValueType.ToString(), color.White, color.DarkMagenta, false);
                                    this.stext(">", color.Cyan, color.DarkMagenta, false);
                                    this.stext(ssl.globals[d].strIndex, color.Cyan, color.Black, false);
                                    this.stext("[", color.Cyan, color.Black, false);
                                    this.stext(ssl.globals[d].Index.ToString(), color.White, color.Black, false);
                                    this.stext("]", color.Cyan, color.Black, false);
                                    Console.Write(": ");
                                    this.stext(ssl.globals[d].Value.ToString(), color.Green, color.Black, false);
                                    Console.WriteLine("");
                                }
                                this.sline("[Stored Globals]", "-", color.Red, color.DarkRed, color.White, color.Black);
                                break;
                            case "assign2":
                                for (int c = 0; c < ca.list[i].subsets.Count(); c++)
                                {
                                    if (ssl.scripts.find_index(ca.list[i].subsets[c].eq) != -1)
                                    {
                                        int asdf = this.add_command(ca.list[i].subsets[c].name, "");
                                        this.commands[asdf].script = ssl.scripts[ca.list[i].subsets[c].eq].name;
                                    }
                                }                                    
                                break;
                        }
                        for (int s = 0; s < ssl.scripts.count; s++)
                        {
                            switch (ca.list[i].name)
                            {

                                case "setvar":
                                    for (int c = 0; c < ca.list[i].subsets.Count(); c++)
                                    {
                                        ssl.scripts[s].set_var(ca.list[i].subsets[c].name, ca.list[i].subsets[c].eq);
                                    }
                                    break;
                                case "dvar":
                                    this.sline("[" + ssl.scripts[s].name + "]", "-", color.Green, color.DarkGreen, color.White, color.Black);
                                    for (int d = 0; d < ssl.scripts[s].vars.count; d++)
                                    {
                                        if (ssl.scripts[s].vars[d].Static == true)
                                        {
                                            this.stext("STATIC", color.Blue, color.Black, false);
                                        }
                                        this.stext("<", color.Cyan, color.DarkMagenta, false);
                                        this.stext(ssl.scripts[s].vars[d].ValueType.ToString(), color.White, color.DarkMagenta, false);
                                        this.stext(">", color.Cyan, color.DarkMagenta, false);
                                        this.stext(ssl.scripts[s].vars[d].strIndex, color.Cyan, color.Black, false);
                                        this.stext("[", color.Cyan, color.Black, false);
                                        this.stext(ssl.scripts[s].vars[d].Index.ToString(), color.White, color.Black, false);
                                        this.stext("]", color.Cyan, color.Black, false);
                                        Console.Write(": ");
                                        this.stext(ssl.scripts[s].vars[d].Value.ToString(), color.Green, color.Black, false);
                                        Console.WriteLine("");
                                    }
                                    this.sline("[" + ssl.scripts[s].name + "]", "-", color.Red, color.DarkRed, color.White, color.Black);

                                    break;
                                case "staticvar":
                                    for (int c = 0; c < ca.list[i].subsets.Count(); c++)
                                    {
                                        //ssl.scripts[s].vars[ca.list[i].subsets[c].name].Static = Convert.ToBoolean(ca.list[i].subsets[c].eq);
                                    }
                                    break;
                                case "setglobal":
                                    for (int c = 0; c < ca.list[i].subsets.Count(); c++)
                                    {
                                        ssl.add_global(ca.list[i].subsets[c].name, ca.list[i].subsets[c].eq);
                                    }
                                    break;
                            }
                        }
                    }
                    if (ca.list.Count() == 0)
                    {
                        for (int c = 0; c < ssl.scripts.count; c++)
                        {
                            stext(string.Format("{0}: ", ssl.scripts[c].name), color.Yellow, color.Black, true);
                            for (int l = 0; l < ssl.scripts[c].lines.Count(); l++)
                            {
                                stext(string.Format("    Line[{1}]: {0}", ssl.scripts[c].lines[l], l), color.Green, color.Black, true);
                            }
                        }
                    }
                    break;
                #endregion
                case "scripteditor":
                    ssl.load_editor();
                    break;
                default:
                    bool suc = false;
                    for (int com = 0; com < this.commands.Count(); com++)
                    {
                        if (this.commands[com] != null)
                        {
                            if (this.commands[com].name == ca.name)
                            {
                                for (int i = 0; i < ssl.scripts.count; i++)
                                {
                                    if (ssl.scripts[i].name == this.commands[com].script)
                                    {
                                        this.ssl.scripts[i].run();
                                        suc = true;

                                    }
                                }
                            }
                        }
                    }
                    if (suc == false)fail = true;
                    break;
            }
            if (fail == true)
            {
                serror(ca.raw_command);
                fail = false;
            }
            return ret;

        }
        public void serror(string com)
        {

            Console.ForegroundColor = ConsoleColor.Red;
            Console.BackgroundColor = ConsoleColor.Black;
            Console.WriteLine("'{0}': Unrecognized Command! Type /? for command list.",com);

        }
        public void anykey(string strTo)
        {
            stext("Press any key to " + strTo + "...", color.DarkRed, color.Black,true);
            Console.ReadKey();
        }
        public void chelp()
        {
            int hw = Console.BufferWidth / 2;
            sline("HELP", "-", color.Blue, color.DarkBlue, color.Yellow, color.DarkYellow);
            foreach (COMMANDS taco in commands)
            {
                try
                {
                    stext(taco.name, color.White, color.Black, true);
                    foreach (string de in taco.desc)
                    {
                        stext("      -" + de, color.Gray, color.Black, true);
                    }
                }
                catch (NullReferenceException n)
                {
                    n.ToString();
                }
            }
            sline("HELP", "-", color.Blue, color.DarkBlue, color.Yellow, color.DarkYellow);
        }
        public void sline(string strString, string strLine, color line_for_color, color line_back_color, color string_for_color, color string_back_color)
        {
            string strTLine="";
            int line_width = (((Console.BufferWidth / strLine.Length)/2) - strString.Length) ;
            for (int i = 0; i < (((Console.BufferWidth / strLine.Length) / 2) - strString.Length); i++)
            {
                strTLine = strTLine + strLine;
            }
            stext(strTLine, line_for_color, line_back_color,false);
            stext(strString, string_for_color, string_back_color,false);
            stext(strTLine, line_for_color, line_back_color,false);
            stext("",color.Black,color.Black,true);
        }
        public void stext(string strString,color string_for_color, color string_back_color,bool line){
            Console.ForegroundColor = (ConsoleColor)string_for_color;
            Console.BackgroundColor = (ConsoleColor)string_back_color;
            if (line == false)
            {
                Console.Write(strString);
            }
            else
            {
                Console.WriteLine(strString);
            }
        }
    }
}
